package client.net;

import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.channels.*;

public class Connection implements Runnable {

	private Selector selector;
	private SocketChannel socketChannel;
	private BufferUtils buffers;
	
	public Connection(String host, int port) {
		try {
			selector = Selector.open();	
			socketChannel = SocketChannel.open();
			socketChannel.configureBlocking(false);
			socketChannel.connect(new InetSocketAddress(host, port));
			socketChannel.register(selector, SelectionKey.OP_CONNECT);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//setDaemon(true); TODO uncomment when the other client threads are established
	}

	public void run() {
		while (true) {
			try {
				selector.select();
				for(SelectionKey selectionKey : selector.selectedKeys()) {
					if (!selectionKey.isValid()) {
						continue;
					}
					if (selectionKey.isConnectable()) {
						socketChannel = (SocketChannel)selectionKey.channel();
						if(socketChannel == null) {
							break;
						}
						socketChannel.finishConnect();
						selectionKey.interestOps(SelectionKey.OP_READ);
						System.out.println("Connection established.");
					} else if (selectionKey.isReadable()) {
						handleIncomingData();
					} 
				}
			} catch(ConnectException e) {
				System.out.println("Cannot connect to server.");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void disconnect() {
		try {
			socketChannel.close();
			System.out.println("Disconnected from server.");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public final void handleIncomingData() {
		try {
			if (socketChannel.read(buffers.getInBuffer()) == -1) {
				disconnect();
				return;
			}
			buffers.getInBuffer().flip();
			while (buffers.getInBuffer().hasRemaining()) {
				System.out.println(buffers.getInBuffer().get());
			}
			buffers.getInBuffer().clear();
		} catch (Exception ex) {
			ex.printStackTrace();
			disconnect();
		}
	}

	public void sendBuffer() {
		buffers.getOutBuffer().flip();
		try {
			socketChannel.write(buffers.getOutBuffer());
		} catch (IOException ex) {
			ex.printStackTrace();
			disconnect();
		}
	}

	public String getHost() {
		return socketChannel.socket().getInetAddress().getHostAddress();
	}

	public SocketChannel getSocketChannel() {
		return socketChannel;
	}
	
	public BufferUtils getBuffers() {
		return buffers;
	}
	
}
